package com.czk.run.generateclass;

import com.czk.utils.FileUtil;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;

import static org.objectweb.asm.Opcodes.*;

/**
 * @Author:ChenZhangKun
 * @Date: 2021/7/23 15:22
 */
public class GenerateHelloWrold_2 {
    public static void main(String[] args) {
        String filePath = "F:\\IdeaProjects\\asm\\target\\classes\\com\\czk\\sample\\Generate_2.class";
        System.out.println(filePath);
        // 生成字节码
        byte[] bye = generate();
        FileUtil.writeBytes(filePath, bye);
    }

    private static byte[] generate() {
        // 创建classWriter对象
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
        cw.visit(V1_8,
                ACC_PUBLIC + ACC_SUPER,
                "sample/Generate_2",
                null,
                "java/lang/Object",
                null
        );
        // 访问方法 构造
        {
            MethodVisitor methodVisitor = cw.visitMethod(ACC_PUBLIC, // 访问标识
                    "<init>", // 构造方法
                    "()V", // 方法描述
                    null, // 签名
                    null);// 是否抛出异常
            // 开始访问代码标记
            methodVisitor.visitCode();
            // local varable 第一个，this对象
            methodVisitor.visitVarInsn(ALOAD, 0);
            methodVisitor.visitMethodInsn(INVOKESPECIAL, // 构造方法
                    "java/lang/Object", // 继承自父类
                    "<init>", // 构造描述
                    "()V",
                    false); // 不是接口
            // 返回
            methodVisitor.visitInsn(RETURN);
            // 最大栈深和局部变量
            methodVisitor.visitMaxs(1, 1);
            methodVisitor.visitEnd();
        }
        {
            MethodVisitor methodVisitor = cw.visitMethod(ACC_STATIC, // 访问标记
                    "<clinit>", // 静态代码块
                    "()V", // 方法描述
                    null, // 签名
                    null); // 异常集合
            methodVisitor.visitCode();
            methodVisitor.visitFieldInsn(
                    GETSTATIC,
                    "java/lang/System",
                    "out",
                    "Ljava/io/PrintStream"
            );
            methodVisitor.visitLdcInsn("class initialization method");
            methodVisitor.visitMethodInsn(INVOKEVIRTUAL,
                    "java/io/PrintStream",
                    "println",
                    "(Ljava/lang/String;)V",
                    false);
            methodVisitor.visitInsn(RETURN);
            // 使用ClassWriter.COMPUTE_FRAMES会忽略我们传入的值，即使是正确的asm也会自动计算
            // 虽然会自动计算，但是也要我们调用一次
            methodVisitor.visitMaxs(2, 0);
            methodVisitor.visitEnd();
        }
        cw.visitEnd();
        return cw.toByteArray();
    }
}
